﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Globalization;
using System.Collections;

namespace Serna
{
    internal static class ObjectsFactory
    {
        static ReaderWriterLockSlim _sync = new ReaderWriterLockSlim();
        static Dictionary<string, ObjectDefinition> dObjs = new Dictionary<string, ObjectDefinition>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ObjectDefinition GetObjectDefinition(object obj)
        {
            return GetObjectDefinition(obj.GetType());
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ObjectDefinition GetObjectDefinition(Type objType)
        {
            ObjectDefinition od = null;

            _sync.EnterUpgradeableReadLock();
            try
            {
                Type t = objType;
                string strType = t.ToString();

                if (!dObjs.TryGetValue(strType, out od))
                {
                    _sync.EnterWriteLock();
                    try
                    {
                        if (!dObjs.TryGetValue(strType, out od))    //Recheck after entering the write locks
                        {
                            od = ParseObject(t);
                            dObjs[strType] = od;
                        }
                    }
                    finally
                    {
                        _sync.ExitWriteLock();
                    }
                }
            }
            finally
            {
                _sync.ExitUpgradeableReadLock();
            }

            return od;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static bool IsClassAnonymous(Type type)
        {
            if (type.IsGenericType)
            {
                var d = type.GetGenericTypeDefinition();
                if (d.IsClass && d.IsSealed && d.Attributes.HasFlag(TypeAttributes.NotPublic))
                {
                    var attributes = d.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false);
                    if (attributes != null && attributes.Length > 0)
                    {
                        //We have an anonymous type
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xstr"></param>
        /// <returns></returns>
        static int CustomStringToInt32(string xstr)
        {
            int y = 0;

            for (int ii = 0; ii < xstr.Length; ii++)
            {
                y = y * 10 + (xstr[ii] - '0');
            }
           
            return y;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="attribute"></param>
        /// <returns></returns>
        static Tuple<int[],int> SplitArrayAttribute(string attribute)
        {
            StringBuilder sb = new StringBuilder();
            int[] dim = new int[10];
            int i = -1;
            foreach (var c in attribute)
            {
                if (c == ' ' && sb.Length>0)
                {
                    i++;
                    dim[i] = CustomStringToInt32(sb.ToString());
                    sb.Clear();
                }
                else
                {
                    sb.Append(c);
                }
            }

            if (sb.Length > 0)  //Las element
            {
                i++;
                dim[i] = CustomStringToInt32(sb.ToString());
                sb.Clear();
            }
            return new Tuple<int[], int>(dim, i);
        }

       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="attribute"></param>
        /// <param name="arrayType"></param>
        /// <returns></returns>
        public static object GetArrayInstance(string attribute, Type arrayType)
        {
            string[] dims = attribute.Split(' ');
           //var res = SplitArrayAttribute(attribute);

            switch (dims.Length)
            {
                case 1:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays1D()(arrayType, CustomStringToInt32(dims[0]) + 1);
                case 2:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays2D()(arrayType, CustomStringToInt32(dims[0]) + 1, CustomStringToInt32(dims[1]) + 1);
                case 3:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays3D()(arrayType, CustomStringToInt32(dims[0]) + 1, CustomStringToInt32(dims[1]) + 1, CustomStringToInt32(dims[2]) + 1);
            }

            throw new Exception("GetArrayInstance Unsupported array rank");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        static ObjectDefinition ParseObject(Type t)
        {
            ObjectDefinition obj = new ObjectDefinition();
            obj.ObjectName = t.FullName;
            obj.ObjectType = t;

            //Getting instance creator
            if (!t.IsArray)
            {
                if (!IsClassAnonymous(t))
                    obj.InstanceCreator = ExpressionBasedReflection.GetInstanceCreator(t);
            }           

            if(t.IsArray)
            {                
                obj.Description = ObjectDefinition.eObjectDescription.Array;
                obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;
                obj.GenericArgument1 = t.GetElementType();
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);             
                return obj;
            }

           // ConcurrentDictionary
            //Special cases (IDict, Ilist,Iset, arrays)
            if (t.GetInterface(typeof(IDictionary<,>).Name) != null)
            {
                obj.Description = ObjectDefinition.eObjectDescription.Dictionary;                

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];
                obj.GenericArgument2 = arguments[1];

                //For the Dictionary
                obj.Dictionary_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericDictionary(t);

                //If key or value are Complex Types, correspondent converter will stay null
                obj.keyTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);

                if(obj.keyTypeFromStringConverter == null)
                    throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Dictionary key can't get type converter");

                obj.keyTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);


                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument2);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument2);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }
            else if (t.GetInterface(typeof(IDictionary).Name) != null)
            {
                throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Unsupported type (non generic Dictionary)");
            }            

            if (t.GetInterface(typeof(IList<>).Name) != null)
            {
                obj.Description = ObjectDefinition.eObjectDescription.List;
                obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];

                //For the List
                obj.List_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericList(t);
                //If key or value are Complex Types, correspondent converter will stay null          
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }
            else if (t.GetInterface(typeof(IList).Name) != null)
            {
                throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Unsupported type (non generic List)");
            }


            if (t.GetInterface(typeof(ISet<>).Name) != null)
            {

                obj.Description = ObjectDefinition.eObjectDescription.HashSet;
                obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];               

                //For the List
                obj.HashSet_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericHashSet(t);
                //If key or value are Complex Types, correspondent converter will stay null          
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }


            
            

            obj.Description = ObjectDefinition.eObjectDescription.CustomClass;

            PropertyDefinition pd = null;

            foreach (FieldInfo field in t.GetFields())
            {
                if (field.FieldType == typeof(object))
                    continue;

                if (field.FieldType.IsArray && field.FieldType != typeof(byte[]))
                {                    
                    obj.Properties.Add(field.Name, new PropertyDefinition
                    {
                        Getter = ExpressionBasedReflection.GetFieldGetter(field),
                        Setter = ExpressionBasedReflection.GetFieldSetter(field),
                        Type = field.FieldType,
                        Mode = PropertyDefinition.eProperty.Array
                        //Type = field.FieldType,
                        //Mode = PropertyDefinition.eProperty.Array,
                        //TypeConverterFromString = GetTypeConverterFromString(field.FieldType.GetElementType()),
                        //TypeConverterToString = GetTypeConverterToString(field.FieldType.GetElementType()),
                        //ArrayRank = field.FieldType.GetArrayRank()
                    });
                }              
                else
                {
                    obj.Properties.Add(field.Name, new PropertyDefinition
                    {
                        Getter = ExpressionBasedReflection.GetFieldGetter(field),
                        Setter = ExpressionBasedReflection.GetFieldSetter(field),
                        Type = field.FieldType,
                        Mode = PropertyDefinition.eProperty.Field,
                        TypeConverterFromString = GetTypeConverterFromString(field.FieldType),
                        TypeConverterToString = GetTypeConverterToString(field.FieldType)
                    });
                }
            }
                        
            foreach (PropertyInfo prop in t.GetProperties().Where(r=>r.CanRead && r.CanWrite))
            {
                if (prop.PropertyType == typeof(object))
                    continue;

                if (prop.PropertyType.IsArray && prop.PropertyType != typeof(byte[]))
                {
                    pd = new PropertyDefinition()
                    {
                        Getter = ExpressionBasedReflection.GetPropertyGetter(prop),
                        Setter = ExpressionBasedReflection.GetPropertySetter(prop),
                        Type = prop.PropertyType,
                        Mode = PropertyDefinition.eProperty.Array,
                        //TypeConverterFromString = GetTypeConverterFromString(prop.PropertyType.GetElementType()),
                        //TypeConverterToString = GetTypeConverterToString(prop.PropertyType.GetElementType()),                                                
                    };
                }
                else
                {
                    pd = new PropertyDefinition()
                    {
                        Type = prop.PropertyType,
                        Mode = PropertyDefinition.eProperty.Property,
                        TypeConverterFromString = GetTypeConverterFromString(prop.PropertyType),
                        TypeConverterToString = GetTypeConverterToString(prop.PropertyType),
                        Getter = ExpressionBasedReflection.GetPropertyGetter(prop),
                        Setter = ExpressionBasedReflection.GetPropertySetter(prop)
                    };
                }
                obj.Properties.Add(prop.Name, pd);
               
            }

            return obj;

        }//eom

      
        #region "Type Converter ToString"


        /// <summary>
        /// Key is TypeFullName, Value is converter to string for static types
        /// </summary>
        static Dictionary<string, Action<StringBuilder, object>> dStaticTypeConverters = new Dictionary<string, Action<StringBuilder, object>>();
        static ReaderWriterLockSlim _sync_dStaticTypeConverters = new ReaderWriterLockSlim();

        /// <summary>
        /// !!!!!!!!!!!!!!!!!!!   here it's possible to add Dynamic DateTime converter
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Action<StringBuilder, object> GetToStringConverterForStaticType(Type t)
        {
            Action<StringBuilder, object> res = null;

            _sync_dStaticTypeConverters.EnterUpgradeableReadLock();
            try
            {
               
                string strType = t.ToString();

                if (!dStaticTypeConverters.TryGetValue(strType, out res))
                {
                    _sync_dStaticTypeConverters.EnterWriteLock();
                    try
                    {
                        if (!dStaticTypeConverters.TryGetValue(strType, out res))
                        {
                            res = GetTypeConverterToString(t);
                            dStaticTypeConverters[strType] = res;
                        }
                    }
                    finally
                    {
                        _sync_dStaticTypeConverters.ExitWriteLock();
                    }
                }
            }
            finally
            {
                _sync_dStaticTypeConverters.ExitUpgradeableReadLock();
            }

            return res;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        public static Action<StringBuilder, object> GetTypeConverterToString(Type t)
        {

           

            if (t == typeof(System.Int16))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                    {                        
                        sb.Append(((System.Int16)p1).ToString());                        
                    };

                return f;
            }
            else if (t == typeof(System.Int16?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((System.Int16)p1).ToString());
                 
                };

                return f;
            }

            if (t == typeof(System.DateTime))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
               
                    sb.Append(((System.DateTime)p1).Ticks);
                
                };

                return f;
            }
            else if (t == typeof(System.DateTime?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                  
                    sb.Append(((System.DateTime)p1).Ticks);
                  
                };

                return f;
            }

            else if (t == typeof(System.UInt16))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                   
                    sb.Append(((System.UInt16)p1).ToString());
                  
                };

                return f;
            }
            else if (t == typeof(System.UInt16?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                  
                    sb.Append(((System.UInt16)p1).ToString());
                  
                };

                return f;
            }

            else if (t == typeof(System.Int32))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((System.Int32)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.Int32?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((System.Int32)p1).ToString());
                    
                };

                return f;
            }

            else if (t == typeof(System.UInt32))
            {

                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((System.UInt32)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.UInt32?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((System.UInt32)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.Int64))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((System.Int64)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.Int64?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((System.Int64)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.UInt64))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((System.UInt64)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.UInt64?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((System.UInt64)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.String))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    foreach(var c in (System.String)p1)
                    {
                        switch (c)
                        {
                            case '\\':
                                sb.Append('\\');
                                sb.Append('\\');
                                break;
                            case '\'':
                                sb.Append('\\');
                                sb.Append('\'');
                                break;
                            default:
                                sb.Append(c);
                                break;
                        }
                    }
                  
                    
                };

                return f;
            }

            else if (t == typeof(System.Char))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {                  
                    
                    char c = (System.Char)p1;

                    switch (c)
                    {
                        case '\\':
                            sb.Append('\\');
                            sb.Append('\\');
                            break;
                        case '\'':
                            sb.Append('\\');
                            sb.Append('\'');
                            break;
                        default:
                            sb.Append(c);
                            break;
                    }
                    
                };

                return f;
            }
            else if (t == typeof(System.Char?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    char c = (System.Char)p1;

                    switch (c)
                    {
                        case '\\':
                            sb.Append('\\');
                            sb.Append('\\');
                            break;
                        case '\'':
                            sb.Append('\\');
                            sb.Append('\'');
                            break;
                        default:
                            sb.Append(c);
                            break;
                    }
                    
                };

                return f;
            }

            else if (t == typeof(double))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                                        
                    sb.Append(((double)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(double?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((double)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }

            else if (t == typeof(float))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((float)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(float?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((float)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }


            else if (t == typeof(decimal))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((decimal)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(decimal?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((decimal)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }

            else if (t == typeof(bool))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append((bool)p1 ? "1" : "0");
                    
                };

                return f;
            }
            else if (t == typeof(bool?))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append((bool)p1 ? "1" : "0");
                    
                };

                return f;
            }

            else if (t == typeof(byte))
            {
                //!!!!!!!!!! must be changed together with byte[] to store only HEX

                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((byte)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(byte?))
            {
                //!!!!!!!!!! must be changed together with byte[] to store only HEX

                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((byte)p1).ToString());
                    
                };

                return f;
            }

            else if (t == typeof(sbyte))
            {
                //!!!!!!!!!! must be changed together with byte[] to store only HEX

                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    
                    sb.Append(((sbyte)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(sbyte?))
            {
                //!!!!!!!!!! must be changed together with byte[] to store only HEX

                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    if (p1 == null)
                        return;
                    
                    sb.Append(((sbyte)p1).ToString());
                    
                };

                return f;
            }


            else if (t.IsEnum)
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                    sb.Append(Convert.ToInt64(p1).ToString());                  
                };

                return f;
            }


            else if (t == typeof(byte[]))
            {
                Action<StringBuilder, object> f = (sb, p1) =>
                {
                      if (p1 == null)
                        return;

                    sb.Append(ToHex((byte[])p1));
                };

                return f;
            }

            return null;
        }
        #endregion

        /// <summary>
        /// Used by ToBytesString
        /// </summary>
        static readonly char[] _hexDigits = "0123456789ABCDEF".ToCharArray();

        /// <summary>
        /// To pure HEX string without delimiters
        /// </summary>
        /// <param name="dBytes"></param>
        /// <returns></returns>
        static string ToHex(byte[] dBytes)
        {
            if (dBytes == null || dBytes.Length == 0)
                return String.Empty;


            ////fastest performance (3.2 x faster then BitConverter) needs _hexDigits
            char[] digits = new char[dBytes.Length * 2];
            int d1, d2;
            for (int i = 0; i < dBytes.Length; i++)
            {
                d2 = dBytes[i] % 16;
                d1 = dBytes[i] / 16;
                digits[2 * i] = _hexDigits[d1];
                digits[2 * i + 1] = _hexDigits[d2];
            }
            return new string(digits);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];

            for (int i = 0; i < NumberChars; i += 2)
            {
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            }
            return bytes;
        }


        #region "Type Converter FromString"
        /// <summary>
        /// Key is TypeFullName, Value is converter to string for static types
        /// </summary>
        static Dictionary<string, Func<string, Tuple<bool, object>>> dStaticTypeConvertersFromString = new Dictionary<string, Func<string, Tuple<bool, object>>>();
        static ReaderWriterLockSlim _sync_dStaticTypeConvertersFromString = new ReaderWriterLockSlim();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Func<string, Tuple<bool, object>> GetFromStringConverterForStaticType(Type t)
        {
            Func<string, Tuple<bool, object>> res = null;

            _sync_dStaticTypeConvertersFromString.EnterUpgradeableReadLock();
            try
            {

                string strType = t.ToString();

                if (!dStaticTypeConvertersFromString.TryGetValue(strType, out res))
                {
                    _sync_dStaticTypeConvertersFromString.EnterWriteLock();
                    try
                    {
                        if (!dStaticTypeConvertersFromString.TryGetValue(strType, out res))
                        {
                            res = GetTypeConverterFromString(t);
                            dStaticTypeConvertersFromString[strType] = res;
                        }
                    }
                    finally
                    {
                        _sync_dStaticTypeConvertersFromString.ExitWriteLock();
                    }
                }
            }
            finally
            {
                _sync_dStaticTypeConvertersFromString.ExitUpgradeableReadLock();
            }

            return res;
        }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Func<string, Tuple<bool, object>> GetTypeConverterFromString(Type t)
        {
            //!!!!!!!!!!!!!!!!!!!!!!  TO DO IN STRING TYPE DESERIALIZATOR: enum, byte[], datetime UTC/NOT

            

            if(t == typeof(System.Int16))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    Int16 ret = 0;
                    if (Int16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int16?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int16 ret = 0;
                    if (System.Int16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            if (t == typeof(System.DateTime) || t == typeof(System.DateTime?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    DateTime ret = DateTime.Now;

                    if (DateTime.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.DateTime?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    DateTime ret = DateTime.Now;

                    if (DateTime.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.UInt16))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    UInt16 ret = 0;
                    if (UInt16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt16?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt16 ret = 0;
                    if (System.UInt16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.Int32))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    System.Int32 ret = 0;
                    if (System.Int32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int32?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if(p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int32 ret = 0;
                    if (System.Int32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.UInt32))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    System.UInt32 ret = 0;
                    if (System.UInt32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt32?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt32 ret = 0;
                    if (System.UInt32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.Int64))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    System.Int64 ret = 0;
                    if (System.Int64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int64?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int64 ret = 0;
                    if (System.Int64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.UInt64))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    System.UInt64 ret = 0;
                    if (System.UInt64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt64?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt64 ret = 0;
                    if (System.UInt64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.String))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    return new Tuple<bool, object>(true, p1);                   
                };

                return f;
            }

            else if (t == typeof(System.Char))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    return new Tuple<bool, object>(true, p1);
                };

                return f;
            }
            else if (t == typeof(System.Char?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    return new Tuple<bool, object>(true, p1);
                };

                return f;
            }

            else if (t == typeof(double))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    double ret = 0;
                    if (Double.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(double?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    double ret = 0;
                    if (Double.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(float))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    float ret = 0;
                    if (float.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(float?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    float ret = 0;
                    if (float.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(decimal))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    decimal ret = 0;
                    if (decimal.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(decimal?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    decimal ret = 0;
                    if (decimal.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(bool))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    bool ret = false;
                    if(p1=="1")
                        return new Tuple<bool, object>(true, true);
                    else if(p1 == "0")
                        return new Tuple<bool, object>(true, false);
                    else if (bool.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(bool?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    bool ret = false;
                    if (p1 == "1")
                        return new Tuple<bool, object>(true, true);
                    else if (p1 == "0")
                        return new Tuple<bool, object>(true, false);

                    if (bool.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(byte))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    byte ret = 0;
                    if (byte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(byte?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    byte ret = 0;
                    if (byte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(sbyte))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    sbyte ret = 0;
                    if (sbyte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(sbyte?))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    sbyte ret = 0;
                    if (sbyte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            if (t.IsEnum)
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {
                    object ret = Enum.Parse(t, p1, true);
                    return new Tuple<bool, object>(true, ret);
                };

                return f;
            }

            if (t == typeof(System.Byte[]))
            {
                Func<string, Tuple<bool, object>> f = (p1) =>
                {

                    return new Tuple<bool, object>(true, StringToByteArray(p1));
                };

                return f;
            }




            return null;
        }

        #endregion



    }//eoc
}//eon
